package com.rizzo.analytics.services.web.controller.v1;

import com.mangofactory.swagger.annotations.ApiModel;
import com.rizzo.analytics.domain.CountResult;
import com.rizzo.analytics.domain.account.Account;
import com.rizzo.analytics.domain.performance.CallInfo;
import com.rizzo.analytics.domain.performance.Performance;
import com.rizzo.infrastructure.dark.DarkLaunch;
import com.rizzo.infrastructure.performance.Monitor;
import com.rizzo.infrastructure.web.validator.Save;
import com.wordnik.swagger.annotations.Api;
import com.wordnik.swagger.annotations.ApiOperation;
import com.wordnik.swagger.annotations.ApiParam;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Controller;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

@Controller("performanceController")
@RequestMapping(value = "/performance", produces = "application/json")
@Api(value = "/performance", description = "Operations about Performance")
public class PerformanceController extends RizzoController {

    private static final Logger LOGGER = LoggerFactory.getLogger(PerformanceController.class);

    @Monitor(userBound = true)
    @PreAuthorize("hasRole('" + Account.ROLE_USER + "')")
    @DarkLaunch(name = "get-performance")
    @ResponseBody
    @RequestMapping(value = "/{application}", method = RequestMethod.GET, produces = "application/json")
    @ApiOperation(value = "List all real-time performance data",
            notes = "This endpoint provides real-time performance data about an application. " +
                    "This endpoint can only be called when logged in and will only return the " + PAGE_SIZE + " first entries!",
            responseClass = "com.rizzo.analytics.domain.performance.Performance", tags = "performance")
    @ApiModel(type = Performance.class)
    public Performance getPerformance(
            @PathVariable(value = "application")
            @ApiParam(name = "application", required = true,
                    value = "The full name of the application (see output of '/application' for possible values)") String application) {
        final String user = getUsernameFromContext();
        validateApplication(application);
        LOGGER.debug("Called performance of [application : '{}'] and [user : '{}']", application, user);
        return analyticsDelegator.getPerformance(user, application, WILDCARD, WILDCARD, WILDCARD, Integer.parseInt(PAGE_SIZE), 0, CallInfo.CallSort.BY_TIME);
    }

    @Monitor(userBound = true)
    @PreAuthorize("hasRole('" + Account.ROLE_USER + "')")
    @DarkLaunch(name = "save-performance")
    @ResponseBody
    @RequestMapping(value = "/{application}", method = RequestMethod.POST, produces = "application/json")
    @ApiOperation(value = "Save real-time performance data",
            notes = "This endpoint saves real-time performance data about an application. " +
                    "This endpoint can only be called when logged in! " +
                    "Be aware that the provided data should fall within the real-time timeframe. " +
                    "So if you provide old data that is older than (now - performanceTimeStep) it will not be saved. " +
                    "Analyzing real-time data means providing real-time data. " +
                    "The real-time timeframe for a certain application can be set with the /config endpoint!" +
                    "This endpoint will return the amount of calls that were actually saved (i.e. that were in time).",
            responseClass = "com.rizzo.analytics.domain.performance.Performance", tags = "performance")
    // TODO REFACTOR CountResult cuz it says nothing
    public CountResult savePerformance(
            @PathVariable(value = "application")
            @ApiParam(name = "application", required = true,
                    value = "The full name of the application (see output of '/application' for possible values or a new one, " +
                            "no wildcards allowed!)") String application,
            @RequestBody
            @Validated(Save.class)
            @ApiParam(name = "performance", required = true,
                    value = "The performance to save")
            @ApiModel(type = Performance.class) Performance performance) {
        final String user = getUsernameFromContext();
        validateApplication(application);
        LOGGER.debug("Saving performance of [application : '{}'] and [user : '{}']", application, user);
        return analyticsDelegator.savePerformance(user, application, performance);
    }

    @Monitor(userBound = true)
    @PreAuthorize("hasRole('" + Account.ROLE_USER + "')")
    @DarkLaunch(name = "get-performance-with-criteria")
    @ResponseBody
    @RequestMapping(value = "/{application}/{category}", method = RequestMethod.GET, produces = "application/json",
            params = {"instanceName", "instanceIndex", "limit", "offset", "callSort"})
    @ApiOperation(value = "List all paged real-time performance data",
            notes = "This endpoint provides real-time performance data about an application. " +
                    "Results from this endpoint are pageable/sorteable and filterable by category, instanceName, instanceIndex. " +
                    "This endpoint can only be called when logged in!",
            responseClass = "com.rizzo.analytics.domain.performance.Performance", tags = "performance,paged")
    @ApiModel(type = Performance.class)
    public Performance getPerformanceWithCriteria(
            @PathVariable(value = "application")
            @ApiParam(name = "application", required = true,
                    value = "The full name of the application (see output of '/application' for possible values)") String application,
            @PathVariable("category")
            @ApiParam(name = "category", required = true,
                    value = "The category or method of the monitored service (wildcards '*' are allowed but case-sensitive)") String category,
            @RequestParam(value = "instanceName", defaultValue = WILDCARD, required = false)
            @ApiParam(name = "instanceName", defaultValue = WILDCARD, required = false,
                    value = "The instanceName from which the performance data originated (wildcards '*' are allowed)") String instanceName,
            @RequestParam(value = "instanceIndex", defaultValue = WILDCARD, required = false)
            @ApiParam(name = "instanceIndex", defaultValue = WILDCARD, required = false,
                    value = "The instanceIndex from which the performance data originated (wildcards '*' are allowed)") String instanceIndex,
            @RequestParam(value = "limit", defaultValue = PAGE_SIZE, required = false)
            @ApiParam(name = "limit", defaultValue = PAGE_SIZE, required = false, allowableValues = PERFORMANCE_PAGE_LIMIT_RANGE,
                    value = "The page-size/limit of the results") long limit,
            @RequestParam(value = "offset", defaultValue = "0", required = false)
            @ApiParam(name = "offset", defaultValue = "0", required = false,
                    value = "The page-offset of the results") long offset,
            @RequestParam(value = "callSort", defaultValue = "BY_TIME", required = false)
            @ApiParam(name = "callSort", defaultValue = "BY_TIME", required = false, allowableValues = CallInfo.CallSort.allowableValues,
                    value = "Sort by 'time' (when the call occured) or the 'duration' (of the call)") CallInfo.CallSort callSort) {
        final String user = getUsernameFromContext();
        validateApplication(application);
        validatePaging(limit, offset, PERFORMANCE_PAGE_LIMIT_RANGE);
        LOGGER.debug("Called performance of [application : '{}'] and [user : '{}'] for [category : '{}']", application, user, category);
        return analyticsDelegator.getPerformance(user, application, instanceName, instanceIndex, category, limit, offset, callSort);
    }

}
